package com.ktwlrj.core.feign.safetyimpl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.ktwlrj.core.feign.strategy.safety.ISafetyStrategy;
import com.ktwlrj.core.util.convert.ConvertUtil;
import feign.RequestTemplate;
import feign.Util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;

/**
 * 会员中心数据签名实现
 *
 * @author zhouxuanhong
 * @date 2019-06-14 13:48
 * @since JDK1.8
 */
@Component("mcSign")
@Slf4j
public class McSignImpl implements ISafetyStrategy {
    private static final String POST = "POST";
    private static final String GET = "GET";
    @Value("${mc.signature-key}")
    private String signatureKey;

    /**
     * 生成签名字段
     *
     * @param map       ${@link SortedMap}
     * @param key       ${@link String}
     * @param timestamp ${@link String}
     * @return String ${@link String}
     * @author zhouxuanhong
     * @date 2019-06-14 14:30
     */
    private static String encodeSign(SortedMap<String, String> map, String key, String timestamp) {
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Iterator<Map.Entry<String, String>> iterator = entries.iterator();
        List<String> values = Lists.newArrayList();
        while (iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            String v = String.valueOf(entry.getValue());
            String k = String.valueOf(entry.getKey());
            if (StringUtils.isNotEmpty(v) && entry.getValue() != null && !"sign".equals(k) && !"key".equals(k)) {
                String decode = null;
                try {
                    decode = URLDecoder.decode(v, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                values.add(k + "=" + decode);
            }
        }
        values.add("timestamp=" + timestamp);
        values.add("key=" + key);
        String sign = StringUtils.join(values, "&");
        log.debug("------------McSignImpl------生成签名前参数------>encodeSign:{}", sign);
        sign = encodeByMD5(sign).toUpperCase();
        log.debug("------------McSignImpl------生成签的签名------>encodeSign:{}", sign);
        return sign;
    }


    /**
     * MD5加密
     *
     * @param algorithmStr ${@link String}
     * @return String ${@link String}
     * @author zhouxuanhong
     * @date 2019-06-14 14:30
     */
    private static String encodeByMD5(String algorithmStr) {
        if (algorithmStr == null) {
            return null;
        }
        return DigestUtils.md5Hex(algorithmStr);
    }


    @Override
    public void handleSafety(RequestTemplate template) {
        String method = template.method();
        if (POST.equalsIgnoreCase(method)) {
            handlePost(template);
        } else if (GET.equalsIgnoreCase(method)) {
            handleGet(template);
        }
    }


    /**
     * 处理post请求加签
     *
     * @param template ${@link RequestTemplate}
     * @author zhouxuanhong
     * @date 2019-06-14 13:57
     */
    private void handlePost(RequestTemplate template) {
        byte[] body = template.body();
        if (body.length > 0) {
            String bodyStr = new String(body, Util.UTF_8);
            if (StringUtils.isNotBlank(bodyStr)) {
                // 数据处理
                JSONObject jsonObject = JSON.parseObject(bodyStr);
                HashMap<String, String> map = ConvertUtil.map(jsonObject, HashMap.class);
                System.out.println("----------McSignImpl---------->handlePost:" + map);
                SortedMap<String, String> sort = new TreeMap<>(map);
                // 生成签名并回填到请求参数中
                String timestamp = Long.toString(System.currentTimeMillis());
                String sign = encodeSign(sort, signatureKey, timestamp);
                jsonObject.put("sign", sign);
                jsonObject.put("timestamp", timestamp);
                body = JSONObject.toJSONString(jsonObject).getBytes(Util.UTF_8);
            }
        }
        // 重置请求体参数
        template.body(body, Util.UTF_8);
    }


    /**
     * 处理get请求加签
     *
     * @param template ${@link RequestTemplate}
     * @author zhouxuanhong
     * @date 2019-06-14 13:57
     */
    private void handleGet(RequestTemplate template) {
        Map<String, Collection<String>> queries = new LinkedHashMap<>(template.queries());
        if (!queries.isEmpty()) {
            log.debug("----------McSignImpl---------->handleGet,加签前数据:{}", queries);
            // 数据处理
            TreeMap<String, String> treeMap = new TreeMap<>();
            queries.forEach((k, v) -> {
                String value = new ArrayList<>(v).get(0);
                treeMap.put(k, value);
            });
            // 生成签名并回填到请求参数中
            String timestamp = Long.toString(System.currentTimeMillis());
            String sign = encodeSign(treeMap, signatureKey, timestamp);
            System.out.println("------------McSignImpl------签名------>handleGet:" + sign);
            List<String> signList = new ArrayList<>();
            signList.add(sign);
            queries.put("sign", signList);
            List<String> timestampList = new ArrayList<>();
            timestampList.add(timestamp);
            queries.put("timestamp", timestampList);
            log.debug("----------McSignImpl---------->handleGet,加签后数据:{}", queries);
        }
        // 重置请求地址参数
        template.queries(null);
        template.queries(queries);
    }
}
